﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.Metadata.Entity.DataModel
{ /// <summary>
  /// 领域模型
  /// </summary>
    [Serializable]
    public partial class CompositeDataObject : AbsMetaDataContent, ISchema
    {
        /// <summary>
        /// ID
        /// </summary>       
        public string ID { get; set; }

        /// <summary>
        /// Code
        /// </summary>       
        public string Code { get; set; }

        /// <summary>
        /// 名称
        /// </summary>       
        public string Name { get; set; }

        /// <summary>
        /// 所属DB.id
        /// </summary>       
        public string DatabaseID { get; set; }

        private CompositeNodeObject rootCompositeNodeObject;

        /// <summary>
        /// 根节点领域对象，json序列化忽略，以CompositeNodeObjects为基础构建重新引用关系
        /// </summary>
        [JsonIgnore]
        [JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Ignore)]
        public CompositeNodeObject RootCompositeNodeObject
        {
            get
            {
                return rootCompositeNodeObject;
            }
            set
            {
                rootCompositeNodeObject = value;
                if (value != null)
                {
                    rootCompositeNodeObject.IsRootObject = true;
                    RootCompositeNodeObjectID = value.ID;
                }
            }
        }

        /// <summary>
        /// 根节点领域对象ID
        /// </summary>
        public string RootCompositeNodeObjectID { get; set; }

        //领域对象集合   
        private List<CompositeNodeObject> compositeNodeObjects;

        /// <summary>
        /// 领域对象集合，json序列化保留，以CompositeNodeObjects为基础构建重新引用关系
        /// </summary>        
        public List<CompositeNodeObject> CompositeNodeObjects
        {
            get
            {
                if (compositeNodeObjects == null)
                    compositeNodeObjects = new List<CompositeNodeObject>();

                return compositeNodeObjects;
            }
            set
            {
                compositeNodeObjects = value;
            }
        }

        /// <summary>
        /// 是否缓存
        /// </summary>
        public bool IsCache { get; set; }

        /// <summary>
        /// 缓存策略
        /// </summary>
        public string CacheStrategy { get; set; }

        /// <summary>
        /// 是否逻辑删除,True:是，false:否
        /// </summary>
        public bool IsLogicDelete { get; set; }

        /// <summary>
        /// 数据加载配置
        /// </summary>
        public string DataLoaderConfig { get; set; }

        /// <summary>
        /// 版本
        /// </summary>
        public int Version { get; set; }

       
        /*******************FAS低代码平台新增字段*******************/
        /// <summary>
        /// CDO是否启用变更日志
        /// </summary>
        public bool EnableChangeLog { get; set; }

        /// <summary>
        /// 租户id
        /// </summary>
        public string TenantID { get; set; }

        /// <summary>
        /// 备用字段
        /// </summary>
        public string Ext1 { get; set; }

        /// <summary>
        /// 备用字段
        /// </summary>
        public string Ext2 { get; set; }

        /// <summary>
        /// 备用字段
        /// </summary>
        public string Ext3 { get; set; }

        /// <summary>
        /// 创建人
        /// </summary>
        //[DataMember]
        public override string Creator { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>        
        //[DataMember]
        public override DateTime CreateTime { get; set; }

        /// <summary>
        /// 最后修改人
        /// </summary>
        //[DataMember]
        public override string LastModifier { get; set; }

        /// <summary>
        /// 最后修改时间
        /// </summary>        
        //[DataMember]
        public override DateTime LastModifyTime { get; set; }


        /*******************CompositeDataObject方法*******************/

        /// <summary>
        /// 重排领域对象，运行时用到了，不可删除
        /// </summary>
        /// <remarks>
        /// 将CDO节点拉平（以root为首）后倒序排列。目的是为了CDO节点生成Delete语句时，从叶子结点开始生成，改变Delete的执行顺序
        /// </remarks>
        public List<CompositeNodeObject> ReverseCompositeNodeObjects()
        {
            var modelObjects = new List<CompositeNodeObject>();
            if (this.RootCompositeNodeObject == null)
                return modelObjects;
            modelObjects.Add(this.RootCompositeNodeObject);

            foreach (var childObject in this.RootCompositeNodeObject.ChildCompositeNodeObjects)
            {
                modelObjects.Add(childObject);
                if (childObject.ChildCompositeNodeObjects.Count > 0)
                {
                    Reverse(childObject, modelObjects);
                }
            }

            modelObjects.Reverse();

            return modelObjects;
        }

        private void Reverse(CompositeNodeObject modelObject, List<CompositeNodeObject> modelObjects)
        {
            if (modelObject.ChildCompositeNodeObjects.Count > 0)
            {
                foreach (var childObject in modelObject.ChildCompositeNodeObjects)
                {
                    modelObjects.Add(childObject);
                }
            }
        }

        /// <summary>
        /// 构造领域对象之间的关联关系。
        /// 从Redis中拉取模型后需要以CompositeDataObject.DataObjects属性为锚点重新构建模型关系。
        /// 1、DM需要重新构建RootCompositeNodeObject属性
        /// 2、DMO需要重新构建CompositeDataObject、ParentObject、ChildCompositeNodeObjects、内联关系的Association属性（内联模型即为主模型）
        /// </summary>
        public CompositeDataObject BuildModelObjectRelation()
        {
            try
            {
                //构建DM.RootCompositeNodeObject属性
                this.RootCompositeNodeObject = this.CompositeNodeObjects.FirstOrDefault(i => i.ID == this.RootCompositeNodeObjectID);
                //this.RootCompositeNodeObject.CompositeDataObject = this;

                BuildModelObjectRelationNew(this, this.RootCompositeNodeObjectID);

                return this;
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.CDO.InitError, "构建模型间关系失败!", e);
            }
        }

        /// <summary>
        /// 构建新的模型关系，从redis中拉取模型后，关联关系引用无效需要重新构建。以CompositeNodeObjects为基础重新构造领域模型树形结构及引用关系
        /// </summary>
        /// <param name="CompositeDataObject">模型实例</param>
        /// <param name="currentNodeID">当前节点id</param>
        private void BuildModelObjectRelationNew(CompositeDataObject CompositeDataObject, string currentNodeID)
        {
            var current = CompositeDataObject.CompositeNodeObjects.Where(node => string.Equals(node.ID, currentNodeID)).FirstOrDefault();
            if (current == null)
            {
                throw new FasException(DataModelErrorCode.CDO.InitError, $"构建模型关系失败，节点id：{currentNodeID}");
            }
            current.CompositeDataObject = CompositeDataObject; //构建DMO.CompositeDataObject属性关系

            foreach (var ass in current.Associations) //构建DMO.内联关系模型属性关系
            {
                if(string.IsNullOrEmpty(ass.CompositeDataObjectID) || string.IsNullOrEmpty(ass.CompositeNodeObjectID))
                {
                    ass.CompositeDataObjectID = CompositeDataObject.ID;
                    ass.CompositeNodeObjectID = currentNodeID;
                }
                if (ass.AssociateType == AssociateType.InnerJoin)
                {
                    ass.AssoDomaiModel = CompositeDataObject;
                    ass.AssoCompositeNodeObject = CompositeDataObject.CompositeNodeObjects.FirstOrDefault(i => i.ID == ass.AssoCompositeNodeObjectID);
                }
            }

            foreach (var ele in current.Elements)
            {
                if(string.IsNullOrEmpty(ele.CompositeDataObjectID) || string.IsNullOrEmpty(ele.CompositeNodeObjectID))
                {
                    ele.CompositeDataObjectID = CompositeDataObject.ID;
                    ele.CompositeNodeObjectID = currentNodeID;
                }
            }

            //对ChildCompositeNodeObjects进行统一排序，保证构造select查询时递归生成sql顺序的一致性
            var nodeList = CompositeDataObject.CompositeNodeObjects.Where(node => string.Equals(node.ParentObjectID, currentNodeID)).OrderBy(o => o.ID).ToList();
            if (nodeList != null && nodeList.Count > 0)
            {
                if (current.ChildCompositeNodeObjects == null)
                    current.ChildCompositeNodeObjects = new List<CompositeNodeObject>();
                else
                    current.ChildCompositeNodeObjects.Clear();   //舍弃原先的子节点关系
                current.ChildCompositeNodeObjects.AddRange(nodeList); //重新构建DMO.ChildCompositeNodeObjects属性关系
                foreach (var item in current.ChildCompositeNodeObjects)
                {
                    item.ParentObject = current; //构建DMO.ParentObject属性关系
                    BuildModelObjectRelationNew(CompositeDataObject, item.ID);
                }
            }
        }

        /// <summary>
        /// 打断领域对象之间的关联关系
        /// </summary>
        public CompositeDataObject BreakModelObjectRelation()
        {
            //置空需要重构引用关系的属性
            foreach (var modelObject in this.CompositeNodeObjects)
            {
                var childObjects = this.CompositeNodeObjects.Where(i => i.ParentObjectID == modelObject.ID);
                if (childObjects != null)
                {
                    foreach (var tempObject in childObjects)
                    {
                        tempObject.ParentObject = null;
                        tempObject.CompositeDataObject = null;
                        foreach (var ass in tempObject.Associations)
                        {
                            if (ass.AssociateType == AssociateType.InnerJoin)
                            {
                                ass.AssoDomaiModel = null;
                                ass.AssoCompositeNodeObject = null;
                            }
                        }
                    }
                }
            }

            this.RootCompositeNodeObject = null;

            return this;
        }



        /// <summary>
        /// 重载ToString方法
        /// </summary>
        /// <remarks>
        /// 方便调试
        /// </remarks>
        /// <returns>CO通用中间对象概述</returns>
        public override string ToString()
        {
            return string.Format("ID: {0}, Name: {1}, RootNode: {2}, Nodes: {3}", ID, Name, this.RootCompositeNodeObject.Name, CompositeNodeObjects.Count);
        }

        public override object Clone()
        {
            return this.MemberwiseClone();
        }
    }
}
